package org.andlisp.android;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Hashtable;

import jp.tyas.libs.terminal.BaseTerminal;
import jp.tyas.libs.terminal.Terminal;
import android.util.AttributeSet;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.text.Editable;
import android.text.InputType;
import android.text.method.KeyListener;
import android.text.method.TextKeyListener;

import java.util.Vector;

public class TerminalView extends View implements Terminal, BaseTerminal.TextUpdatedListener, SharedPreferences.OnSharedPreferenceChangeListener
{
  final static String LOG_TAG = "TerminalView";
  public final static String KEY_TEXT_POS_X = "pos.x";
  public final static String KEY_TEXT_POS_Y = "pos.y";
  public final static String KEY_TEXT_PAINT = "text.paint";

  private BaseTerminal term = null;
  private KeyListener keyl = TextKeyListener.getInstance();
  private Editable text = Editable.Factory.getInstance().newEditable("");

  public TerminalView (Context ctx) {
    this(ctx, null);
  }

  public TerminalView (Context ctx, AttributeSet attrs) {
    this(ctx, attrs, R.style.terminal_style_default);
  }
  
  public TerminalView (Context ctx, AttributeSet attrs, int defStyle) {
    super(ctx, attrs, defStyle);

    Hashtable props = new Hashtable();
    props.put(KEY_TEXT_POS_X, SafePreferenceManager.getInt(ctx, "MarginLeft", 0));
    props.put(KEY_TEXT_POS_Y, SafePreferenceManager.getInt(ctx, "MarginTop", 0));

    TextPaint tp = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    props.put(KEY_TEXT_PAINT, tp);
    tp.setColor(Color.parseColor(SafePreferenceManager.getString(ctx, "ForegroundColor", "YELLOW")));
    tp.setTextSize((float)SafePreferenceManager.getInt(ctx, "FontSize", 11));

    setBackgroundColor(Color.parseColor(SafePreferenceManager.getString(ctx, "BackgroundColor", "BLACK")));

    /*
    TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.terminal, defStyle, 0);
    int len = a.length();
    for (int i = 0; i < len; i++) {
      switch (a.getIndex(i)) {
      case R.styleable.terminal_foreground:
        tp.setColor(a.getColor(i, R.color.DefaultTerminalForeground));
        break;
      case R.styleable.terminal_margin_top:
        props.put(KEY_TEXT_POS_Y, a.getInt(i, R.integer.DefaultTerminalMarginTop));
        break;
      case R.styleable.terminal_margin_left:
        props.put(KEY_TEXT_POS_X, a.getInt(i, R.integer.DefaultTerminalMarginLeft));
        break;
      }
    }
    a.recycle();
    */

    term = new BaseTerminal(0, props);
    term.setTextUpdatedListener(this);

    this.setFocusable(true);
    this.setFocusableInTouchMode(true);
    android.preference.PreferenceManager
      .getDefaultSharedPreferences(ctx).registerOnSharedPreferenceChangeListener(this);
  }

  public boolean onTouchEvent(MotionEvent e) {
    if (e.getAction() == MotionEvent.ACTION_DOWN) {
      Log.d(LOG_TAG, "onTouchEvent(" + e.toString() + ")");
      InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
      imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
      //requestFocus();
    }
    return super.onTouchEvent(e);
  }

  public synchronized void textUpdated() {
    this.postInvalidate();
  }
	
  public Terminal.Connection openConnection() {
    return term.openConnection();
  }

  public boolean onCheckIsTextEditor() {
    return true;
  }

  public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    outAttrs.actionLabel = null;
    outAttrs.hintText = "Insert S expression.";
    outAttrs.initialCapsMode = 0;
    outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
    outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
    outAttrs.imeOptions=EditorInfo.IME_ACTION_DONE;
    return new BaseInputConnection(this, true) {
      public boolean sendKeyEvent(KeyEvent e) {
        Log.d(LOG_TAG, "sendKeyEvent(" + e.toString() + ")");
        if (e.getAction() != KeyEvent.ACTION_DOWN)
          return super.sendKeyEvent(e);
        Editable ed = getEditable();
        switch (e.getKeyCode()) {
        case KeyEvent.KEYCODE_ENTER:
          term.putStringIn(ed);
          term.putCharIn('\n');
          ed.clear();
          break;
        case KeyEvent.KEYCODE_DEL:
          int pos = ed.length() - 1;
          if (pos >= 0) {
            ed.delete(pos, pos+1);
            textUpdated();
          }
          break;
        default:
          break;
        }
        return super.sendKeyEvent(e);
      }
      public Editable getEditable() {
        Log.d(LOG_TAG, "'" + TerminalView.this.text + "' == getEditable()");
        return TerminalView.this.text;
      }
      public boolean commitText(CharSequence text, int cur) {
        boolean ret = super.commitText(text, cur);
        textUpdated();
        return ret;
      }
    };
  }

  protected void onFocusChanged(boolean gainFocus, int direct, Rect prev) {
    InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
  }

  public void onDraw(Canvas c) {
    super.onDraw(c);
    Paint textp = (Paint)term.getProperty(KEY_TEXT_PAINT);
    float txh = textp.getTextSize();
    int stax = (Integer)term.getProperty(KEY_TEXT_POS_X);
    int stay = (Integer)term.getProperty(KEY_TEXT_POS_Y);
    int max = (int)((getHeight() - stay) / txh);
    int start = term.size() - max;
    int i;
    if (start < 0) {
      start = 0;
      max = term.size();
    }
    for (i = 0; i < max - 1; i++)
      c.drawText(term.getLine(start+i), stax, stay + i*txh, textp);
    c.drawText(term.getLine(start+i) + text + "<", stax, stay + i*txh, textp);
  }

  public boolean onKeyDown(int code, KeyEvent e)
  {
    boolean ret = super.onKeyDown(code, e);
    Log.d(LOG_TAG, ret + " == onKeyDown(" + code + ", " + e.toString() + ")");
    return ret;
  }

  public boolean onKeyUp(int code, KeyEvent e)
  {
    boolean ret = super.onKeyUp(code, e);
    Log.d(LOG_TAG, ret + " == onKeyUp(" + code + ", " + e.toString() + ")");
    return ret;
  }

  /*
  public boolean onKeyDown(int code, KeyEvent e) {
    super.onKeyDown(code, e);
    Log.d(LOG_TAG, "onKeyDown(" + e.toString() + ")");
    if (code == KeyEvent.KEYCODE_ENTER) {
      term.putStringIn(text);
      term.putCharIn('\n');
      text.clear();
    } else {
      keyl.onKeyDown(this, text, code, e);
      textUpdated();
    }
    return true;
  }

  public boolean onKeyUp(int code, KeyEvent e) {
    super.onKeyUp(code, e);
    Log.d(LOG_TAG, "onKeyUp(" + e.toString() + ")");
    return keyl.onKeyUp(this, text, code, e);
  }
  */

  public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
    if ("ForegroundColor".equals(key)) {
      ((Paint)term.getProperty(KEY_TEXT_PAINT)).setColor(SafePreferenceManager.getColor(sp, key, "YELLOW"));
      postInvalidate();
    }
    else if ("BackgroundColor".equals(key)) {
      setBackgroundColor(SafePreferenceManager.getColor(sp, key, "BLACK"));
      postInvalidate();
    }
    else if ("FontSize".equals(key)) {
      ((Paint)term.getProperty(KEY_TEXT_PAINT)).setTextSize((float)SafePreferenceManager.getInt(sp, key, 11));
      postInvalidate();
    }
    else if ("MarginTop".equals(key)) {
      term.setProperty(KEY_TEXT_POS_Y, Integer.valueOf(SafePreferenceManager.getInt(sp, key, 0)));
      postInvalidate();
    }
    else if ("MarginLeft".equals(key)) {
      term.setProperty(KEY_TEXT_POS_X, Integer.valueOf(SafePreferenceManager.getInt(sp, key, 0)));
      postInvalidate();
    }
  }
}
